// process part implementation is from https://github.com/mitchellh/go-ps
// so you can see his code for more information
package process

import (
	"fmt"
	"os"
	"time"

	"go-cmd/top/mem"
)

var cpuMap map[int]uint64 // pid->last cpu timestamp

func init() {
	cpuMap = make(map[int]uint64)
}

type Process interface {
	Pid() int
	PPid() int       // the parent process pid
	Execute() string // executeable name running this process
	Memory() (uint64, error)
	Cpu() (uint64, error) // cpu usage time
}

type ProcessProperty struct {
	Pid        int
	PPid       int
	MemPercent float64
	CpuPercent float64
	Exec       string
}

func Processes(duration int) ([]ProcessProperty, error) {
	ps, err := processes()

	ret := make([]ProcessProperty, 0)
	if err != nil {
		fmt.Printf("get processes failed, err=%s\n", err)
		os.Exit(1)
	}
	for _, p := range ps {
		memSize, err := p.Memory()
		if err != nil {
			if err.Error() == "Access is denied." || err.Error() == "The parameter is incorrect." {
				continue
			} else {
				return nil, err
			}
		}

		currTimestamp, err := p.Cpu()
		if err != nil {
			return nil, err
		}
		lastTimestamp, ok := cpuMap[p.Pid()]
		if !ok {
			lastTimestamp = currTimestamp
		}
		cpuMap[p.Pid()] = currTimestamp

		x := ProcessProperty{
			Pid:        p.Pid(),
			PPid:       p.PPid(),
			MemPercent: (float64(memSize) / float64(mem.TOTAL_MEM_SIZE)) * 100,
			CpuPercent: float64(currTimestamp-lastTimestamp) / float64(time.Duration(duration)*time.Second) * 100000,
			Exec:       p.Execute(),
		}
		ret = append(ret, x)
	}
	return ret, nil
}

func FindProcess(pid int) (Process, error) {
	return findProcess(pid)
}
